package _9_博客园Redis

import (
	"fmt"
	"github.com/go-redis/redis"
)

/*发布者和订阅者都是Redis客户端，Channel则为Redis服务器端，发布者将消息发送到某个的频道，订阅了这个频道的订阅者就能接收到这条消息。
Redis的这种发布订阅机制与基于主题的发布订阅类似，Channel相当于主题。
下面介绍golang如何使用redis的发布订阅功能。
go redis发布订阅常用函数：
	Subscribe - 订阅channel
	PSubscribe - 订阅channel支持通配符匹配
	Publish - 将信息发送到指定的channel。
	PubSubChannels - 查询活跃的channel
	PubSubNumSub - 查询指定的channel有多少个订阅者*/

func main() {
	//(0)初始化一个新的redis client
	client := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379", // redis地址
		Password: "",               // redis没密码，没有设置，则留空
		DB:       0,                // 使用默认数据库
	})

	//(1)Subscribe订阅channel例子1：
	// 订阅channel1这个channel
	sub := client.Subscribe("channel1")

	// 读取channel消息
	iface, err := sub.Receive()
	if err != nil {
		// handle error
	}

	// 检测收到的消息类型
	switch iface.(type) {
	case *redis.Subscription:
		// 订阅成功
	case *redis.Message:
		// 处理收到的消息
		// 这里需要做一下类型转换
		m := iface.(redis.Message)
		// 打印收到的小
		fmt.Println(m.Payload)
	case *redis.Pong:
		// 收到Pong消息
	default:
		// handle error
	}

	//例子2： 使用golang channel的方式处理消息

	// 订阅channel1这个channel
	sub2 := client.Subscribe("channel1")

	// sub.Channel() 返回go channel，可以循环读取redis服务器发过来的消息
	for msg := range sub2.Channel() {
		// 打印收到的消息
		fmt.Println(msg.Channel)
		fmt.Println(msg.Payload)
	}

	//例子3： 取消订阅
	// 订阅channel1这个channel
	sub3 := client.Subscribe("channel1")

	// 忽略其他处理逻辑

	// 取消订阅
	sub3.Unsubscribe("channel1")

	//(2)PSubscribe用法跟Subscribe一样，区别是PSubscribe订阅通道(channel)支持模式匹配。例子：

	// 订阅channel1这个channel
	sub4 := client.PSubscribe("ch_user_*")
	fmt.Println(sub4)
	// 可以匹配ch_user_开头的任意channel

	//(3)Publish将消息发送到指定的channel
	// 将"message"消息发送到channel1这个通道上
	client.Publish("channel1", "message")

	//(4)PubSubChannels查询活跃的channel
	// 没有指定查询channel的匹配模式，则返回所有的channel
	chs, _ := client.PubSubChannels("").Result()
	for _, ch := range chs {
		fmt.Println(ch)
	}

	// 匹配user_开头的channel
	chsl, _ := client.PubSubChannels("user_*").Result()
	fmt.Println(chsl)
	//(5)PubSubNumSub查询指定的channel有多少个订阅者

	// 查询channel1，channel2两个通道的订阅者数量
	chsk, _ := client.PubSubNumSub("channel1", "channel2").Result()
	for ch, count := range chsk {
		fmt.Println(ch)    // channel名字
		fmt.Println(count) // channel的订阅者数量
	}
}
